<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>第12章 实战：三天开发一个管理端 | 深入理解Vue.js实战</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="作者：被删">
    
    <link rel="preload" href="/vue-ebook/assets/css/0.styles.77f3552e.css" as="style"><link rel="preload" href="/vue-ebook/assets/js/app.2f410bb9.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/2.d60fd2a5.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/3.c15c8d98.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/11.6bf1fc64.js" as="script">
    <link rel="stylesheet" href="/vue-ebook/assets/css/0.styles.77f3552e.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/vue-ebook/" class="home-link router-link-active"><!----> <span class="site-name">深入理解Vue.js实战</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前言</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/0.html" class="sidebar-link">前端框架的出现</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>第一部分 Vue快速入门</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/1.html" class="sidebar-link">第1章 Vue 框架介绍</a></li><li><a href="/vue-ebook/vue-ebook/2.html" class="sidebar-link">第2章 Vue 环境快速搭建</a></li><li><a href="/vue-ebook/vue-ebook/3.html" class="sidebar-link">第3章 Vue 基础介绍</a></li><li><a href="/vue-ebook/vue-ebook/4.html" class="sidebar-link">第4章 Vue 组件的使用</a></li><li><a href="/vue-ebook/vue-ebook/5.html" class="sidebar-link">第5章 常用指令和自定义指令</a></li><li><a href="/vue-ebook/vue-ebook/6.html" class="sidebar-link">第6章 Vue 动画</a></li><li><a href="/vue-ebook/vue-ebook/7.html" class="sidebar-link">第7章 Vue Router 路由搭建应用</a></li><li><a href="/vue-ebook/vue-ebook/8.html" class="sidebar-link">第8章 实战：Todo List 从组件到应用</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>第二部分 Vue的正确使用方式</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/9.html" class="sidebar-link">第9章 思维转变与大型项目管理</a></li><li><a href="/vue-ebook/vue-ebook/10.html" class="sidebar-link">第10章 如何正确地进行抽象</a></li><li><a href="/vue-ebook/vue-ebook/11.html" class="sidebar-link">第11章 全局数据管理与 Vuex</a></li><li><a href="/vue-ebook/vue-ebook/12.html" aria-current="page" class="active sidebar-link">第12章 实战：三天开发一个管理端</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/12.html#_12-1-设计管理端功能" class="sidebar-link">12.1 设计管理端功能</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/12.html#_12-2-组件快速开发" class="sidebar-link">12.2 组件快速开发</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/12.html#_12-3-设计页面与路由" class="sidebar-link">12.3 设计页面与路由</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/12.html#_12-4-路由配置与开发" class="sidebar-link">12.4 路由配置与开发</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/12.html#_12-5-给路由添加鉴权" class="sidebar-link">12.5 给路由添加鉴权</a></li></ul></li><li><a href="/vue-ebook/vue-ebook/13.html" class="sidebar-link">第13章 实战：表单配置化实现</a></li><li><a href="/vue-ebook/vue-ebook/14.html" class="sidebar-link">第14章 实战：使用 Webpack 或 Vue CLI 搭建多页应用</a></li><li><a href="/vue-ebook/vue-ebook/15.html" class="sidebar-link">第15章 Vue 周边拓展</a></li><li><a href="/vue-ebook/vue-ebook/16.html" class="sidebar-link">第16章 关于 Vue 3.0</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>后记</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/99.html" class="sidebar-link">关于框架选型</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="第12章-实战-三天开发一个管理端"><a href="#第12章-实战-三天开发一个管理端" class="header-anchor">#</a> 第12章 实战：三天开发一个管理端</h1> <blockquote><p>本章节相关代码存放在<a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/12" target="_blank" rel="noopener noreferrer">Github<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>中。</p></blockquote> <p>管理端，大概是让大多数前端又爱又恨的一个业务。爱，大概是因为容错能力稍微强一点，对视觉还原要求比较低、业务使用量通常不会很大。恨，大概是因为管理端多半是增删改查的东西，做多了就会变成重复性的工作。</p> <p>但不管你在哪里，管理端都是无法避开的一种项目，所以我们来看看怎么又快又好地搭建这样一个项目。由于是速战速决的项目类型，我们直接选择使用热门的 Element 组件。（请不要误会，这里没有收取广告费，偷懒是人的本性，而选择好用的开源组件库，是优秀的程序员都会做的事情）</p> <p>国内比较热门的组件库大概有 Antd、Element、iView 等，Antd 主要是基于 React.js 的，虽然也支持了 Vue 和 Angular，但整体组件库风格偏自由灵活，而自由灵活往往也是有代价的。Element 和 iView 都是基于 Vue.js 的，而 Element 代码还提供了 codepen 在线调试运行，同时个人感觉文档和布局更舒服，所以就选了 Element，各位其实也可以根据个人喜好或是团队要求来选择使用不同的组件库。</p> <p>好，我们先来设计一下这个管理端的能力吧。</p> <h2 id="_12-1-设计管理端功能"><a href="#_12-1-设计管理端功能" class="header-anchor">#</a> 12.1 设计管理端功能</h2> <p>假设我们要做一个管理端的页面，包括常见的增删查改，那会包括菜单、列表、表单这几种内容，如图 12-1：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-1.jpg" alt=""><br>
图 12-1 管理端效果</p> <p>既然要使用数据驱动的方式，那么我们先来设计这个页面的数据包括哪些。关于数据和组件抽象的方法，已经在<a href="/vue-ebook/vue-ebook/10.html">《第10章 抽象的正确姿势》</a>有详细地介绍。我们可以先根据页面设计来分隔模块和组件，然后根据组件抽象来设计数据。用数据驱动的模式来进行开发，这样整个思路会更加清晰一点，我们一个个来看具体怎么做。</p> <h3 id="_12-1-1-菜单设计"><a href="#_12-1-1-菜单设计" class="header-anchor">#</a> 12.1.1 菜单设计</h3> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-2.jpg" alt=""><br>
图 12-2 菜单实现效果</p> <p>如图 12-2，我们能看到，菜单列表主要包括父菜单列表，每个父菜单包括：</p> <ul><li>图标 icon</li> <li>菜单名字 text</li> <li>（可选）子菜单列表 subMenus，以及子菜单名字 text</li></ul> <p>所以，我们可以抽象出这么一个数据结构:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> menus <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    text<span class="token operator">:</span> <span class="token string">&quot;服务管理&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 父菜单名字</span>
    icon<span class="token operator">:</span> <span class="token string">&quot;el-icon-setting&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 父菜单图标</span>
    subMenus<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;服务信息&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;新增&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token comment">// 子菜单列表</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    text<span class="token operator">:</span> <span class="token string">&quot;产品管理&quot;</span><span class="token punctuation">,</span>
    icon<span class="token operator">:</span> <span class="token string">&quot;el-icon-menu&quot;</span><span class="token punctuation">,</span>
    subMenus<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;产品信息&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    text<span class="token operator">:</span> <span class="token string">&quot;日志信息&quot;</span><span class="token punctuation">,</span>
    icon<span class="token operator">:</span> <span class="token string">&quot;el-icon-message&quot;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_12-1-2-列表设计"><a href="#_12-1-2-列表设计" class="header-anchor">#</a> 12.1.2 列表设计</h3> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-3.jpg" alt=""><br>
图 12-3 列表实现效果</p> <p>如图，我们能看到，列表里每行内容包括：</p> <ul><li>日期: date</li> <li>姓名: name</li> <li>电话: phone</li> <li>地址: address</li></ul> <p>我们可以先整理到这么一个数据：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> tableItem <span class="token operator">=</span> <span class="token punctuation">{</span>
  date<span class="token operator">:</span> <span class="token string">&quot;2019-05-20&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 日期</span>
  name<span class="token operator">:</span> <span class="token string">&quot;被删&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 姓名</span>
  phone<span class="token operator">:</span> <span class="token string">&quot;13888888888&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 电话</span>
  address<span class="token operator">:</span> <span class="token string">&quot;深圳市南山区滨海大道 888 号&quot;</span> <span class="token comment">// 地址</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>而在列表这样的增删查改的场景下，一般还需要一个唯一标识来作为标记，这里使用 id，用最简单的方式来拷贝出 20 个数据：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 此处先以 tableItem 为数据源，拷贝生成 20 个数据，然后再根据索引 index 添加上 id</span>
<span class="token keyword">const</span> tableData <span class="token operator">=</span> <span class="token function">Array</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>tableItem<span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> id<span class="token operator">:</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">...</span>x <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>tableData<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 例如第 2 个数据为：</span>
<span class="token comment">/* {
    address: &quot;深圳市南山区滨海大道 888 号&quot;
    date: &quot;2019-05-20&quot;
    id: 2
    name: &quot;被删&quot;
    phone: &quot;13888888888&quot;
} */</span>
</code></pre></div><h3 id="_12-1-3-方法"><a href="#_12-1-3-方法" class="header-anchor">#</a> 12.1.3 方法</h3> <p>关于 Vue 的 methods 方法，如果说数据是状态机的话，那事件大概可以当成状态机的扭转。这里以列表作为举例吧，例如新增、删除、上移、下移，我们只需要处理数据就好了：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 绑定数据</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      menus<span class="token operator">:</span> menus<span class="token punctuation">,</span> <span class="token comment">// 菜单数据</span>
      tableData<span class="token operator">:</span> tableData <span class="token comment">// 列表数据</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  methods<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// 新增一个数据</span>
    <span class="token function">addTableItem</span><span class="token punctuation">(</span><span class="token parameter">item <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 添加到列表中，同时自增 id</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>item<span class="token punctuation">,</span> id<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span>length <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// 删除一个数据</span>
    <span class="token function">deleteTableItem</span><span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 查找到对应的索引，然后删除</span>
      <span class="token keyword">const</span> index <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">.</span>id <span class="token operator">===</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token comment">// 移动一个数据</span>
    <span class="token function">moveTableItem</span><span class="token punctuation">(</span><span class="token parameter">id<span class="token punctuation">,</span> direction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> dataLength <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
      <span class="token comment">// 查找到对应的索引，然后取出，再插入</span>
      <span class="token keyword">const</span> index <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">.</span>id <span class="token operator">===</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">switch</span> <span class="token punctuation">(</span>direction<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 上移</span>
        <span class="token keyword">case</span> <span class="token string">&quot;up&quot;</span><span class="token operator">:</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 第一个不进行上移</span>
            <span class="token keyword">const</span> item <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>index <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> item<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
          <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token comment">// 下移</span>
        <span class="token keyword">case</span> <span class="token string">&quot;down&quot;</span><span class="token operator">:</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">&lt;</span> dataLength <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 最后一个不进行下移</span>
            <span class="token keyword">const</span> item <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>tableData<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> item<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
          <span class="token keyword">break</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>当我们把数据更新了之后，Vue 会自动帮我们更新到页面里，具体是怎么实现的，可以参考<a href="/vue-ebook/vue-ebook/1.html">第1章</a>里数据绑定的实现、虚拟 DOM 的相关内容。</p> <h2 id="_12-2-组件快速开发"><a href="#_12-2-组件快速开发" class="header-anchor">#</a> 12.2 组件快速开发</h2> <p>既然设计好了数据结构和状态改变，我们可以直接绑定 HTML 了。因为使用的 Element 的组件，其实我们只需要从他们的网站上找到合适的组件，然后根据他们提供的配置说明，来搭建出我们想要的效果就好了。</p> <h3 id="_12-2-1-菜单绑定"><a href="#_12-2-1-菜单绑定" class="header-anchor">#</a> 12.2.1 菜单绑定</h3> <p>我们先来看看 Elmenet 里的菜单是怎么用的，可以参考 Element-NavMenu 导航菜单文档，这里我们只列出我们可能用到的一些配置（感兴趣的小伙伴，也可以去 Github 上翻一下源码看看别人的组件是怎么抽象和配置化管理的），<code>&lt;el-menu&gt;</code>、<code>&lt;el-submenu&gt;</code>和<code>&lt;el-menu-item&gt;</code>的配置如下：</p> <p>表 12-1 <code>&lt;el-menu&gt;</code>参数配置</p> <table><thead><tr><th>参数</th> <th>说明</th> <th>类型</th> <th>可选值</th> <th>默认值</th></tr></thead> <tbody><tr><td>mode</td> <td>模式</td> <td>string</td> <td>horizontal/vertical</td> <td>vertical</td></tr> <tr><td>collapse</td> <td>是否水平折叠收起菜单（仅在 mode 为 vertical 时可用）</td> <td>boolean</td> <td>—</td> <td>false</td></tr> <tr><td>background-color</td> <td>菜单的背景色（仅支持 hex 格式）</td> <td>string</td> <td>—</td> <td>#ffffff</td></tr> <tr><td>text-color</td> <td>菜单的文字颜色（仅支持 hex 格式）</td> <td>string</td> <td>—</td> <td>#303133</td></tr> <tr><td>active-text-color</td> <td>当前激活菜单的文字颜色（仅支持 hex 格式）</td> <td>string</td> <td>—</td> <td>#409EFF</td></tr> <tr><td>default-active</td> <td>当前激活菜单的 index</td> <td>string</td> <td>—</td> <td>—</td></tr> <tr><td>default-openeds</td> <td>当前打开的 sub-menu 的 index 的数组</td> <td>Array</td> <td>—</td> <td>—</td></tr> <tr><td>unique-opened</td> <td>是否只保持一个子菜单的展开</td> <td>boolean</td> <td>—</td> <td>false</td></tr></tbody></table> <p>表 12-2 <code>&lt;el-submenu&gt;</code>参数配置</p> <table><thead><tr><th>参数</th> <th>说明</th> <th>类型</th> <th>可选值</th> <th>默认值</th></tr></thead> <tbody><tr><td>index</td> <td>唯一标志</td> <td>string/null</td> <td>—</td> <td>null</td></tr></tbody></table> <p>表 12-3 <code>&lt;el-menu-item&gt;</code>参数配置</p> <table><thead><tr><th>参数</th> <th>说明</th> <th>类型</th> <th>可选值</th> <th>默认值</th></tr></thead> <tbody><tr><td>index</td> <td>唯一标志</td> <td>string</td> <td>—</td> <td>—</td></tr></tbody></table> <p>我们来看看代码，可以仔细看注释噢：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- default-openeds 为默认展开的菜单项，以 index 序号 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu</span> <span class="token attr-name">:default-openeds</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>[<span class="token punctuation">'</span>1<span class="token punctuation">'</span>, <span class="token punctuation">'</span>3<span class="token punctuation">'</span>]<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- el-submenu 为带子菜单的父菜单，index 为每组菜单的序号 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-submenu</span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>1<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 下面是父菜单内容，包括父菜单 icon 和父菜单名字 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>el-icon-message<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">&gt;</span></span>导航一<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item-group</span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 子菜单选项，包括 index 序号和子菜单名字 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>1-1<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>选项1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>1-2<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>选项2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item-group</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-submenu</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- el-menu-item 为不带子菜单的父菜单，index 为每组菜单的序号 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>2<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 父菜单内容，包括父菜单 icon 和父菜单名字 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>el-icon-menu<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>导航二<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>绑定数据之后，就会变成这样：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 顺便调整了下颜色 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu</span>
  <span class="token attr-name">:default-openeds</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>[<span class="token punctuation">'</span>0<span class="token punctuation">'</span>, <span class="token punctuation">'</span>1<span class="token punctuation">'</span>]<span class="token punctuation">&quot;</span></span>
  <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>el-menu-vertical-demo<span class="token punctuation">&quot;</span></span>
  <span class="token attr-name">background-color</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>#545c64<span class="token punctuation">&quot;</span></span>
  <span class="token attr-name">text-color</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>#fff<span class="token punctuation">&quot;</span></span>
  <span class="token attr-name">active-text-color</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>#ffd04b<span class="token punctuation">&quot;</span></span>
<span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- 遍历生成父菜单选项 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu in menus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 有子菜单的时候，就用 el-submenu，再绑个序号 index --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-submenu</span>
      <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.subMenus &amp;&amp; menu.subMenus.length<span class="token punctuation">&quot;</span></span>
      <span class="token attr-name">:index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span>
      <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span>
    <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!-- 绑个父菜单的 icon --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.icon<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!-- 再绑个父菜单的名称 text --&gt;</span>
        <span class="token comment">&lt;!-- slot 其实类似于占位符，可以去 Vue 官方文档了解一下插槽 --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{menu.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item-group</span><span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!-- 子菜单也要遍历，同时绑上子菜单名称 text，也要绑个序号 index --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span>
          <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>subMenu in menu.subMenus<span class="token punctuation">&quot;</span></span>
          <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>subMenu.index<span class="token punctuation">&quot;</span></span>
          <span class="token attr-name">:index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>subMenu.index<span class="token punctuation">&quot;</span></span>
          <span class="token punctuation">&gt;</span></span>{{subMenu.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span>
        <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item-group</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-submenu</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 没子菜单的时候，就用 el-menu-item，也要绑个序号 index --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span> <span class="token attr-name">v-else</span> <span class="token attr-name">:index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 绑个父菜单的 icon --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.icon<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 再绑个父菜单的名称 text --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{menu.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>我们之前的 menus 并没有<code>index</code>，这里可以顺便遍历生成一下：</p> <div class="language-js extra-class"><pre class="language-js"><code>menus <span class="token operator">=</span> menus<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>x<span class="token punctuation">,</span>
    <span class="token comment">// 子菜单就拼接${父菜单index}-${子菜单index}</span>
    subMenus<span class="token operator">:</span> <span class="token punctuation">(</span>x<span class="token punctuation">.</span>subMenus <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">y<span class="token punctuation">,</span> j</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>y<span class="token punctuation">,</span> index<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>j<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token comment">// 父菜单就把 index 加上好了</span>
    index<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>看~菜单成功生成了：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-10.png" alt=""><br>
图 12-4 菜单实现效果</p> <h3 id="_12-2-2-列表绑定"><a href="#_12-2-2-列表绑定" class="header-anchor">#</a> 12.2.2 列表绑定</h3> <p>列表使用的组件是 Element-Table，以及需要按钮 Button 操作。由于 Table 的属性太多，这里就不再贴出来占篇幅，大家可以自行去 Element 的官网（https://element.eleme.cn）里查看。我们把数据绑上，还有按钮以及对应的事件都绑上，就获得这样一份代码：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- data 里绑定表格数据，同时这里调整了下样式 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table</span>
  <span class="token attr-name">stripe</span>
  <span class="token attr-name">:data</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>tableData<span class="token punctuation">&quot;</span></span>
  <span class="token style-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token style language-css"><span class="token property">border</span><span class="token punctuation">:</span> 1px solid #ebebeb<span class="token punctuation">;</span><span class="token property">border-radius</span><span class="token punctuation">:</span> 3px<span class="token punctuation">;</span><span class="token property">margin-top</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span></span><span class="token punctuation">&quot;</span></span></span>
<span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- prop 传绑定 tableData 的数据 id，表头名称 id，同时设了下宽度 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table-column</span> <span class="token attr-name">prop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>id<span class="token punctuation">&quot;</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>id<span class="token punctuation">&quot;</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>100<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- prop 传绑定 tableData 的数据 date，表头名称日期 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table-column</span> <span class="token attr-name">prop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>date<span class="token punctuation">&quot;</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>日期<span class="token punctuation">&quot;</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>200<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- prop 传绑定 tableData 的数据 name，表头名称姓名 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table-column</span> <span class="token attr-name">prop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>name<span class="token punctuation">&quot;</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>姓名<span class="token punctuation">&quot;</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>200<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- prop 传绑定 tableData 的数据 phone，表头名称电话 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table-column</span> <span class="token attr-name">prop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>phone<span class="token punctuation">&quot;</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>电话<span class="token punctuation">&quot;</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>200<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- prop 传绑定 tableData 的数据 address，表头名称地址 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table-column</span> <span class="token attr-name">prop</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>address<span class="token punctuation">&quot;</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>地址<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table-column</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- 该列固定在右侧，表头名称操作 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-table-column</span> <span class="token attr-name">fixed</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>right<span class="token punctuation">&quot;</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>操作<span class="token punctuation">&quot;</span></span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>300<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span> <span class="token attr-name">slot-scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>scope<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 添加了个删除按钮，绑定了前面定义的删除事件 deleteTableItem，传入参数 id --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-button</span>
        <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>deleteTableItem(scope.row.id)<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>danger<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>small<span class="token punctuation">&quot;</span></span>
        <span class="token punctuation">&gt;</span></span>删除<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-button</span>
      <span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 分别添加了上移和下移按钮，绑定了前面定义的移动事件 moveTableItem，传入参数 id 和移动方向 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>moveTableItem(scope.row.id, <span class="token punctuation">'</span>up<span class="token punctuation">'</span>)<span class="token punctuation">&quot;</span></span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>small<span class="token punctuation">&quot;</span></span>
        <span class="token punctuation">&gt;</span></span>上移<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-button</span>
      <span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>moveTableItem(scope.row.id, <span class="token punctuation">'</span>down<span class="token punctuation">'</span>)<span class="token punctuation">&quot;</span></span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>small<span class="token punctuation">&quot;</span></span>
        <span class="token punctuation">&gt;</span></span>下移<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-button</span>
      <span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table-column</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-table</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>然后我们就顺利获得了这样一个列表：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-11.jpg" alt=""><br>
图 12-5 列表实现效果</p> <h3 id="_12-2-3-表单绑定"><a href="#_12-2-3-表单绑定" class="header-anchor">#</a> 12.2.3 表单绑定</h3> <p>有列表的地方，当然也少不了表单。那么，同样的方法，我们直接使用 Element-Form 组件。因为这里打算用弹窗的方式来装这个表单的内容，所以我们也使用了 Element-Dialog 组件，请自行查阅组件属性和配置噢。</p> <p>有了前面数据设计和绑定的基础，这里可以直接给出我们的代码：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 找个地方添加一个新增的按钮，点击的时候出现表单的弹窗，以及把表单内容设置为初始值 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>primary<span class="token punctuation">&quot;</span></span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dialogFormVisible = true;form = {};<span class="token punctuation">&quot;</span></span>
  <span class="token punctuation">&gt;</span></span>新增<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-button</span>
<span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- Form --&gt;</span>
<span class="token comment">&lt;!-- el-dialog 是弹窗样式，title 绑定弹窗的标题内容，visible 绑定弹窗是否展示 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-dialog</span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>新增<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:visible.sync</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dialogFormVisible<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-form</span> <span class="token attr-name">:model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>form<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- el-form-item 绑定表单样式，label 表单的名称，formLabelWidth 设置 label 的宽度 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-form-item</span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>日期<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:label-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formLabelWidth<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 里面装载表单元素，这里装了个选择日期的组件，v-model 绑定选择值，value-format设置绑定值的格式，type 设置选择的范围，这里 date 表示到天 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-date-picker</span>
        <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>form.date<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">value-format</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>yyyy-MM-dd<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>date<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>选择日期<span class="token punctuation">&quot;</span></span>
      <span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-date-picker</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-form-item</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-form-item</span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>姓名<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:label-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formLabelWidth<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>form.name<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-input</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-form-item</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-form-item</span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>电话<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:label-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formLabelWidth<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>form.phone<span class="token punctuation">&quot;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>tel<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-input</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-form-item</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-form-item</span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>地址<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:label-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>formLabelWidth<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>form.address<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-input</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-form-item</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-form</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>footer<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dialog-footer<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 点击取消的时候，设置弹窗不可见 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dialogFormVisible = false<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>取 消<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-button</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 点击确定的时候，设置弹窗不可见，同时添加一项内容 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-button</span>
      <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>primary<span class="token punctuation">&quot;</span></span>
      <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dialogFormVisible = false; addTableItem(form)<span class="token punctuation">&quot;</span></span>
      <span class="token punctuation">&gt;</span></span>确 定<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-button</span>
    <span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-dialog</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>我们需要新增的数据变量包括：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      dialogFormVisible<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment">// 弹窗是否出现</span>
      form<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 用作表单绑定的内容</span>
      formLabelWidth<span class="token operator">:</span> <span class="token string">&quot;120px&quot;</span> <span class="token comment">// 表单 label 的宽度</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>这样，我们的表单就写好了：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-12.jpg" alt=""><br>
图 12-6 表单实现效果</p> <h2 id="_12-3-设计页面与路由"><a href="#_12-3-设计页面与路由" class="header-anchor">#</a> 12.3 设计页面与路由</h2> <p>在直接讲我们的路由怎么配置前，我们需要先知道我们的应用要怎么划分，路由和页面路径是一一对应的，所以我们需要先设计应用的页面逻辑。我们要知道怎么设计一个应用，或者说根据已有的产品、设计交互，怎么规划我们项目的结构。</p> <p>我们看看前面内容的页面效果：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-1.jpg" alt=""><br>
图 12-7 表单实现效果</p> <h3 id="_12-3-1-页面结构设计"><a href="#_12-3-1-页面结构设计" class="header-anchor">#</a> 12.3.1 页面结构设计</h3> <p>这是常用的一种管理端页面结构，我们可以基于这样的页面设计几种类型的页面拼装：</p> <p>表 12-4 几种常用的管理端页面类型</p> <table><thead><tr><th>序号</th> <th>页面形式</th> <th>页面能力</th></tr></thead> <tbody><tr><td>1</td> <td>登录页</td> <td>只有用户名和密码的输入</td></tr> <tr><td>2</td> <td>列表 + 表单</td> <td>单页可以完成某类服务的增删查改</td></tr> <tr><td>3</td> <td>列表页</td> <td>只有列表展示，提供查和删服务，需要配合 4 的表单页完成增和改</td></tr> <tr><td>4</td> <td>表单页</td> <td>只有表单编辑内容，可提供新增、修改等能力给 3 使用</td></tr></tbody></table> <p>上述序号 2 到 4 结构的页面，可以配合路由，整理出这样的菜单信息：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-3-2.jpg" alt=""><br>
图 12-8 几种常用的管理端页面类型</p> <h3 id="_12-3-2-页面路由设计"><a href="#_12-3-2-页面路由设计" class="header-anchor">#</a> 12.3.2 页面路由设计</h3> <p>上述情况下，以<code>/</code>作为根路由（对应的组件为 App.vue），我们设计这么几种路由和页面：</p> <p>表 12-5 页面路由设计</p> <table><thead><tr><th>路由</th> <th>页面内容</th> <th>页面对应的 Component</th> <th>页面组成</th></tr></thead> <tbody><tr><td><code>/login</code></td> <td>登录页</td> <td>Login</td> <td>表单，包括<code>username</code>和<code>password</code></td></tr> <tr><td><code>/home</code></td> <td>应用首页</td> <td>Home</td> <td>左侧菜单<code>&lt;Menu&gt;</code>，右侧路由内容<code>&lt;router-view&gt;</code></td></tr> <tr><td><code>/home/service</code></td> <td>服务信息页</td> <td>Service</td> <td>为 Home 的子路由组件，包括列表和表单</td></tr> <tr><td><code>/home/product</code></td> <td>产品容器页</td> <td>Product</td> <td>为 Home 的子路由组件，包括<code>&lt;router-view&gt;</code></td></tr> <tr><td><code>/home/product/list</code></td> <td>产品信息页</td> <td>ProductList</td> <td>为 Product 的子路由组件，包括列表</td></tr> <tr><td><code>/home/product/edit</code></td> <td>产品编辑页</td> <td>ProductEdit</td> <td>为 Product 的子路由组件，包括表单</td></tr></tbody></table> <p>页面结构和路由嵌套管理，其实是这样的：</p> <div class="language-cmd extra-class"><pre class="language-text"><code>/login                     /home                     /home/service
+------------------+       +-----------------+       +-----------------+
| App              |       | App             |       | App             |
| +--------------+ |       | +-------------+ |       | +-------------+ |
| | Login        | |       | | Home        | |       | | Home        | |
| |              | |       | |             | |       | | +---------+ | |
| |              | |  +--) | |&lt;router-view&gt;| |  +--) | | | Service | | |
| |              | |       | |  无对应内容  | |       | | |列表+表单 | | |
| |              | |       | |             | |       | | +---------+ | |
| +--------------+ |       | +-------------+ |       | +-------------+ |
+------------------+       +-----------------+       +-----------------+


      /home/product                /home/product/list              /home/product/edit
      +---------------------+      +------------------------+      +------------------------+
      | App                 |      | App                    |      | App                    |
      | +-----------------+ |      | +--------------------+ |      | +--------------------+ |
      | | Home            | |      | | Home               | |      | | Home               | |
      | | +-------------+ | |      | | +----------------+ | |      | | +----------------+ | |
 +--) | | | Product     | | | +--) | | | Product        | | | +--) | | | Product        | | |
      | | |&lt;router-view&gt;| | |      | | | +------------+ | | |      | | | +------------+ | | |
      | | |  无对应内容  | | |      | | | | ProductList| | | |      | | | | ProductEdit| | | |
      | | |             | | |      | | | | 单列表页    | | | |      | | | | 单表单页    | | | |
      | | |             | | |      | | | +------------+ | | |      | | | +------------+ | | |
      | | +-------------+ | |      | | +----------------+ | |      | | +----------------+ | |
      | +-----------------+ |      | +--------------------+ |      | +--------------------+ |
      +---------------------+      +------------------------+      +------------------------+

</code></pre></div><p>我们能看到，这里包括了层层的路由嵌套关系，我们后面在配置路由的时候也能看到这样的结构。</p> <h3 id="_12-3-3-目录结构划分"><a href="#_12-3-3-目录结构划分" class="header-anchor">#</a> 12.3.3 目录结构划分</h3> <p>我们看到上面的路由划分示意图，使用框框框起来的代表一个 Vue 组件。而在 Vue 中，其实一切皆组件（页面是特殊的组件），那我们要怎么区分页面和组件呢，一般可以使用项目目录来简单做一些划分：</p> <div class="language-cmd extra-class"><pre class="language-text"><code>├─dist                      // 编译之后的项目文件
├─src                       // 开发目录
│  ├─assets                 // 静态资源
│     ├─less                // 公共less
│     ├─img                 // 图片资源
│  ├─components             // **放这里是组件**
│  ├─pages                  // **放这里是页面** 根据路由结构划分
│  ├─utils                  // 工具库
│  ├─App.vue                // 启动页面，最外层容器组件
│  ├─main.js                // 入口脚本
├─babel.config.js          // babel 配置文件
├─vue.config.js            // vue 自定义配置，与 webpack 配置相关
├─package.json             // 项目配置
├─README.md                // 项目说明
</code></pre></div><p>目录结构清晰，其实对一个项目的可维护性非常重要，一眼看去你就知道这个项目大概包括了哪些内容，分别都放在哪里。好看的目录结构和命名，和好看的代码结构和命名一样，已经是天然的说明了，这是很好的编码习惯。前面<a href="/vue-ebook/vue-ebook/9.html">第9章</a>也有详细讲述这一块的内容，大家可以去复习下。</p> <p>好了，项目目录和路由结构我们划分好了，我们来看看怎么根据上面的设计来配置路由，以及实现相互跳转。</p> <h2 id="_12-4-路由配置与开发"><a href="#_12-4-路由配置与开发" class="header-anchor">#</a> 12.4 路由配置与开发</h2> <p>关于应用路由和 Vue Router 的介绍和使用，已经在<a href="/vue-ebook/vue-ebook/7.html">第7章</a>详细介绍过，这里我们就直接使用了。</p> <h3 id="_12-4-1-配置路由信息"><a href="#_12-4-1-配置路由信息" class="header-anchor">#</a> 12.4.1 配置路由信息</h3> <p>根据以上的嵌套关系，我们可以设置最外层的根路由为<code>&quot;/&quot;</code>，加上其他嵌套子路由配置为：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 配置路由信息</span>
<span class="token comment">// 每个路由应该映射一个组件。 其中&quot;component&quot; 可以是</span>
<span class="token comment">// 通过 Vue.extend() 创建的组件构造器，</span>
<span class="token comment">// 或者，只是一个组件配置对象。</span>
<span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    path<span class="token operator">:</span> <span class="token string">&quot;/&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 父路由路径</span>
    component<span class="token operator">:</span> App<span class="token punctuation">,</span> <span class="token comment">// 父路由组件，传入 vue component</span>
    name<span class="token operator">:</span> <span class="token string">&quot;App&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 路由名称</span>
    <span class="token comment">// 设置子路由</span>
    children<span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        path<span class="token operator">:</span> <span class="token string">&quot;login&quot;</span><span class="token punctuation">,</span> <span class="token comment">// 子路由路径</span>
        component<span class="token operator">:</span> Login<span class="token punctuation">,</span> <span class="token comment">// 子路由组件，会替换父组件中&lt;router-view&gt;中的内容</span>
        name<span class="token operator">:</span> <span class="token string">&quot;Login&quot;</span> <span class="token comment">// 路由名称</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token comment">// 应用首页</span>
        path<span class="token operator">:</span> <span class="token string">&quot;home&quot;</span><span class="token punctuation">,</span>
        component<span class="token operator">:</span> Home<span class="token punctuation">,</span>
        name<span class="token operator">:</span> <span class="token string">&quot;Home&quot;</span><span class="token punctuation">,</span>
        children<span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token comment">// 服务列表</span>
          <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">&quot;service&quot;</span><span class="token punctuation">,</span> component<span class="token operator">:</span> Service<span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">&quot;Service&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token comment">// 产品容器</span>
          <span class="token punctuation">{</span>
            path<span class="token operator">:</span> <span class="token string">&quot;product&quot;</span><span class="token punctuation">,</span>
            component<span class="token operator">:</span> Product<span class="token punctuation">,</span>
            name<span class="token operator">:</span> <span class="token string">&quot;Product&quot;</span><span class="token punctuation">,</span>
            children<span class="token operator">:</span> <span class="token punctuation">[</span>
              <span class="token comment">// 子路由内容</span>
              <span class="token comment">// 产品列表</span>
              <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">&quot;list&quot;</span><span class="token punctuation">,</span> component<span class="token operator">:</span> ProductList<span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">&quot;ProductList&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
              <span class="token comment">// 产品新增</span>
              <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">&quot;add/0&quot;</span><span class="token punctuation">,</span> component<span class="token operator">:</span> ProductEdit<span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">&quot;ProductAdd&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
              <span class="token comment">// 产品编辑</span>
              <span class="token comment">// 我们能看到，新增和编辑其实最终使用的是同一个组件，所以后面会有一些需要兼容处理的地方</span>
              <span class="token comment">// :id可匹配任意值，且可在组件中通过this.$route.params.id获取该值</span>
              <span class="token punctuation">{</span> path<span class="token operator">:</span> <span class="token string">&quot;edit/:id&quot;</span><span class="token punctuation">,</span> component<span class="token operator">:</span> ProductEdit<span class="token punctuation">,</span> name<span class="token operator">:</span> <span class="token string">&quot;ProductEdit&quot;</span> <span class="token punctuation">}</span>
            <span class="token punctuation">]</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_12-4-2-vue-中加载-vue-router-和路由信息"><a href="#_12-4-2-vue-中加载-vue-router-和路由信息" class="header-anchor">#</a> 12.4.2 Vue 中加载 vue-router 和路由信息</h3> <p>路由配置设计好之后，我们可以通过将 router 配置参数注入路由，让整个应用都有路由功能：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 加载路由信息</span>
<span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// mode: 路由模式，'hash' | 'history'</span>
  <span class="token comment">// routes：传入路由配置信息，后面会讲怎么配置</span>
  routes <span class="token comment">// （缩写）相当于 routes: routes</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 启动一个 Vue 应用</span>
<span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  el<span class="token operator">:</span> <span class="token string">&quot;#app&quot;</span><span class="token punctuation">,</span>
  router<span class="token punctuation">,</span> <span class="token comment">// 传入路由能力</span>
  <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token parameter">h</span> <span class="token operator">=&gt;</span> <span class="token function">h</span><span class="token punctuation">(</span>App<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>这里 vue-router 的路由模式<code>mode</code>包括两种：
(1) hash</p> <ul><li>使用 URL hash 值来作路由。支持所有浏览器，包括不支持 HTML5 History Api 的浏览器</li> <li>例如上面说的<code>a.com/#/pageone</code>，便是 hash 模式<br>
(2) history</li> <li>充分利用<code>history.pushState</code> API 来完成 URL 跳转而无须重新加载页面</li> <li>例如<code>a.com/pageone</code>，如果觉得 hash 模式丑可以使用这种</li> <li>**注意！！**该模式依赖 HTML5 History API 和服务器配置</li></ul> <p>到这里，我们路由配置和启动的部分已经完成，可以在https://github.com/godbasin/vue-book-code/tree/master/12/1-element-manage-app/src/main.js文件查看完整代码。</p> <h3 id="_12-4-3-router-view-使用"><a href="#_12-4-3-router-view-使用" class="header-anchor">#</a> 12.4.3 <code>&lt;router-view&gt;</code>使用</h3> <p><code>&lt;router-view&gt;</code>组件是一个 functional 组件，渲染路径匹配到的视图组件。它渲染的组件还可以内嵌自己的<code>&lt;router-view&gt;</code>，根据嵌套路径，渲染嵌套组件。我们来看看<code>&lt;router-view&gt;</code>的使用，这里以 App.vue 和 Home.vue 作为例子：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 这里是最外层 /app 路由的组件，App.vue --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- 使用 &lt;router-view&gt;&lt;/router-view&gt; 来嵌套路由 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-view</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>

<span class="token comment">&lt;!-- 这里是 /app/home 路由的组件，Home.vue --&gt;</span>
<span class="token comment">&lt;!-- 这里采用了简写，省略了一些非关键内容，更多内容可以参考上一节 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-container</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 左侧菜单, Menu.vue --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>menu</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>menu</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 右侧内容 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-container</span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 上边的头部栏 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-header</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-header</span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 子路由页面的内容 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-view</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-container</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-container</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><h3 id="_12-4-4-router-link-使用"><a href="#_12-4-4-router-link-使用" class="header-anchor">#</a> 12.4.4 <code>&lt;router-link&gt;</code>使用</h3> <p>前面我们拼了这么一个页面：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-for-everyone-2-1.jpg" alt=""><br>
图 12-9 目前的页面效果</p> <p>这里左侧的菜单点击没有什么反应，因为我们还没有加上路由。那么现在就使用这里的菜单，来展示下<code>&lt;router-link&gt;</code>的使用吧。</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 这里是 Menu.vue，即上一节内容种拼的左侧菜单 --&gt;</span>
<span class="token comment">&lt;!-- 这里主要针对路由相关内容，更多的注释省略了，有需要可查看最终代码 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token comment">&lt;!-- 此处有个 default-active 属性需要注意，是用来设置菜单的选中样式，我们需要根据当前路由情况来选中 --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu</span>
    <span class="token attr-name">:collapse</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>isMenuCollapse<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name">:default-openeds</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>[<span class="token punctuation">'</span>0<span class="token punctuation">'</span>, <span class="token punctuation">'</span>1<span class="token punctuation">'</span>]<span class="token punctuation">&quot;</span></span>
    <span class="token attr-name">:default-active</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>activeIndex<span class="token punctuation">&quot;</span></span>
  <span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 遍历生成父菜单选项 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu in menus<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 有子菜单的时候 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-submenu</span>
        <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.subMenus &amp;&amp; menu.subMenus.length<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">:index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.icon<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{menu.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item-group</span><span class="token punctuation">&gt;</span></span>
          <span class="token comment">&lt;!-- 使用 router-link 组件来导航. --&gt;</span>
          <span class="token comment">&lt;!-- 通过传入 `to` 属性指定链接. --&gt;</span>
          <span class="token comment">&lt;!-- &lt;router-link&gt; 默认会被渲染成一个 `&lt;a&gt;` 标签 --&gt;</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span>
            <span class="token attr-name">tag</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>div<span class="token punctuation">&quot;</span></span>
            <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>subMenu in menu.subMenus<span class="token punctuation">&quot;</span></span>
            <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>subMenu.index<span class="token punctuation">&quot;</span></span>
            <span class="token attr-name">:to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{name: subMenu.routerName}<span class="token punctuation">&quot;</span></span>
          <span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span> <span class="token attr-name">:index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>subMenu.index<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{subMenu.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item-group</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-submenu</span><span class="token punctuation">&gt;</span></span>
      <span class="token comment">&lt;!-- 只有单个父菜单的时候，也要给这个父菜单添加路由，同样的 to 指向要去的地方 --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span>
        <span class="token attr-name">v-else</span>
        <span class="token attr-name">:index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">:key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.index<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">tag</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>div<span class="token punctuation">&quot;</span></span>
        <span class="token attr-name">:to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{name: menu.routerName}<span class="token punctuation">&quot;</span></span>
      <span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!-- 没子菜单的时候，就用 el-menu-item，也要绑个序号 index --&gt;</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>i</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>menu.icon<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>i</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{menu.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu-item</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>el-menu</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p><code>&lt;router-link&gt;</code>的使用，除了通过 name 来跳转之外，还可通过 path 跳转、带上参数、激活样式、tag 设置等：</p> <p>表 12-6 <code>&lt;router-link&gt;</code>属性配置说明</p> <table><thead><tr><th>配置</th> <th>说明</th></tr></thead> <tbody><tr><td>to</td> <td>一个路径字符串, 或者一个对象 location descriptor</td></tr> <tr><td>tag</td> <td>渲染成的 html 元素类型，默认是<code>&lt;a&gt;</code></td></tr> <tr><td>exact</td> <td>用于控制当前激活项的行为</td></tr> <tr><td>append</td> <td>控制相对链接路径的追加方式</td></tr> <tr><td>replace</td> <td>替代而不是作为历史条目压榨</td></tr> <tr><td>active-class</td> <td>当链接项激活时增加的 CSS 样式</td></tr></tbody></table> <p>更多的大家可以参考官网 router-link 的 API。也可以在https://github.com/godbasin/vue-book-code/tree/master/12/1-element-manage-app/src/components/Menu.vue文件查看Menu组件的完整代码。</p> <h3 id="_12-4-5-使用-watch-监控路由变化"><a href="#_12-4-5-使用-watch-监控路由变化" class="header-anchor">#</a> 12.4.5 使用 watch 监控路由变化</h3> <p>对应的，我们需要在 menus 里加上 routerName，用来跳转：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// routerName 为对应的路由的路由名称</span>
<span class="token keyword">const</span> menus <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    text<span class="token operator">:</span> <span class="token string">&quot;服务管理&quot;</span><span class="token punctuation">,</span>
    icon<span class="token operator">:</span> <span class="token string">&quot;el-icon-setting&quot;</span><span class="token punctuation">,</span>
    subMenus<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;服务信息&quot;</span><span class="token punctuation">,</span> routerName<span class="token operator">:</span> <span class="token string">&quot;Service&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    text<span class="token operator">:</span> <span class="token string">&quot;产品管理&quot;</span><span class="token punctuation">,</span>
    icon<span class="token operator">:</span> <span class="token string">&quot;el-icon-menu&quot;</span><span class="token punctuation">,</span>
    subMenus<span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;产品信息&quot;</span><span class="token punctuation">,</span> routerName<span class="token operator">:</span> <span class="token string">&quot;ProductList&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;新增&quot;</span><span class="token punctuation">,</span> routerName<span class="token operator">:</span> <span class="token string">&quot;ProductAdd&quot;</span> <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// 日志信息这里为空，则不会进行跳转</span>
  <span class="token punctuation">{</span> text<span class="token operator">:</span> <span class="token string">&quot;日志信息&quot;</span><span class="token punctuation">,</span> icon<span class="token operator">:</span> <span class="token string">&quot;el-icon-message&quot;</span><span class="token punctuation">,</span> routerName<span class="token operator">:</span> <span class="token string">&quot;&quot;</span> <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span> i</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// 添加 index，可用于默认展开 default-openeds 属性，和激活状态 efault-active 属性的设置</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>x<span class="token punctuation">,</span>
    <span class="token comment">// 子菜单就拼接${父菜单index}-${子菜单index}</span>
    subMenus<span class="token operator">:</span> <span class="token punctuation">(</span>x<span class="token punctuation">.</span>subMenus <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">y<span class="token punctuation">,</span> j</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>y<span class="token punctuation">,</span> index<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>j<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token comment">// 父菜单就把 index 加上好了</span>
    index<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>根据前面<code>&lt;el-menu&gt;</code>的配置我们知道，<code>default-active</code>属性需要设置当前激活菜单的 index，因此我们需要监控路由的变化，并根据路由情况调整绑定的激活 index。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 下面是 Vue 组件</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      menus<span class="token punctuation">,</span> <span class="token comment">// menus: menus 的简写</span>
      activeIndex<span class="token operator">:</span> <span class="token string">&quot;&quot;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  watch<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// 为了设置 el-menu 的 default-active 属性，需要获取到路由状态</span>
    <span class="token function">$route</span><span class="token punctuation">(</span><span class="token parameter">to</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 对路由变化作出响应...</span>
      <span class="token keyword">let</span> activeIndex<span class="token punctuation">;</span>
      <span class="token comment">// 找到匹配的 routerName</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>menus<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>x<span class="token punctuation">.</span>routerName <span class="token operator">===</span> to<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          activeIndex <span class="token operator">=</span> x<span class="token punctuation">.</span>index<span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> subMenuItem <span class="token operator">=</span> x<span class="token punctuation">.</span>subMenus<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token parameter">y</span> <span class="token operator">=&gt;</span> y<span class="token punctuation">.</span>routerName <span class="token operator">===</span> to<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>subMenuItem<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            activeIndex <span class="token operator">=</span> subMenuItem<span class="token punctuation">.</span>index<span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 并将 activeIndex 设置为对应的 菜单 index</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>activeIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>activeIndex <span class="token operator">=</span> activeIndex<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>我们看到，这里使用了 watch 属性，监听了<code>$route</code>的变化。关于 Vue 中监听属性<code>watch</code>和<code>$route</code>的变化，前面也介绍了，这里就不过多介绍了。</p> <h3 id="_12-4-6-路由跳转"><a href="#_12-4-6-路由跳转" class="header-anchor">#</a> 12.4.6 路由跳转</h3> <p>除了使用<code>&lt;router-link&gt;</code>来定义导航链接，我们还可以借助 router 的实例方法，通过编写代码来实现。在 Vue 实例内部，我们可以通过<code>\$router</code>访问路由实例，例如我们在 ProductList 页面需要跳转到 ProductEdit 页面来编辑/新增选项内容：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...其他省略</span>
  methods<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// 新增/修改一个数据</span>
    <span class="token function">updateTableItem</span><span class="token punctuation">(</span><span class="token parameter">id <span class="token operator">=</span> <span class="token number">0</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 跳转到编辑页面，新增则传id为0，否则为编辑</span>
      <span class="token comment">// 可以通过 this.$router 访问路由实例</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>id <span class="token operator">!==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 传参 name 为路由名字，params 为我们定义的路由 path 的参数，变成 /edit/xxx</span>
        <span class="token comment">// 还有另外一种传参方式 query，带查询参数，变成 /edit?id=xxx</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">&quot;ProductEdit&quot;</span><span class="token punctuation">,</span> params<span class="token operator">:</span> <span class="token punctuation">{</span> id <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">&quot;ProductAdd&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>router 实例的使用和<code>&lt;router-link&gt;</code>其实很相像，也挺简单的，可以参考<a href="/vue-ebook/vue-ebook/7.html">第7章</a>内容，或者上 Vue Router 官网查阅。</p> <h2 id="_12-5-给路由添加鉴权"><a href="#_12-5-给路由添加鉴权" class="header-anchor">#</a> 12.5 给路由添加鉴权</h2> <p>既然我们这一次设计了登录页和应用首页，一般来说，我们会设计只有当登录完成之后，才可以进入应用里面的其他页面。下面是具体的实现方式。</p> <h3 id="_12-5-1-设置简单的全局数据"><a href="#_12-5-1-设置简单的全局数据" class="header-anchor">#</a> 12.5.1 设置简单的全局数据</h3> <p>一般来说，在 Vue 中会使用 Vuex 来管理数据状态。基于篇幅关系，Vuex 在<a href="/vue-ebook/vue-ebook/11.html">第11章</a>详细介绍，所以这里我们简单设计一个全局数据的管理库：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// globalData.js</span>
<span class="token comment">// globalData 用来存全局数据</span>
<span class="token keyword">let</span> globalData <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// 获取全局数据</span>
<span class="token comment">// 传 key 获取对应的值</span>
<span class="token comment">// 不传 key 获取全部值</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getGlobalData</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> key <span class="token operator">?</span> globalData<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">:</span> globalData<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 设置全局数据</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">setGlobalData</span><span class="token punctuation">(</span><span class="token parameter">key<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 需要传键值对</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>key <span class="token operator">===</span> <span class="token keyword">undefined</span> <span class="token operator">||</span> value <span class="token operator">===</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  globalData <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">...</span>globalData<span class="token punctuation">,</span> <span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token operator">:</span> value <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> globalData<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 清除全局数据</span>
<span class="token comment">// 传 key 清除对应的值</span>
<span class="token comment">// 不传 key 清除全部值</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">clearGlobalData</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 需要传键值对</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>key <span class="token operator">===</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    globalData <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token keyword">delete</span> globalData<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> globalData<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>使用这种方式的全局数据，是会在页面刷新之后丢失的。而如果用来存用户的登录态信息，为了避免频繁登录，更好的方式是存到 cookie 或者缓存里。</p> <h3 id="_12-5-2-登录页面登录"><a href="#_12-5-2-登录页面登录" class="header-anchor">#</a> 12.5.2 登录页面登录</h3> <p>拼好的页面可以查看https://github.com/godbasin/vue-book-code/tree/master/12/1-element-manage-app/src/pages/Login.vue文件，这里我们只看保存数据和跳转的部分：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> setGlobalData <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;utils/globalData&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 下面是 Vue 组件</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...其他省略</span>
  methods<span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token comment">// 提交新增/修改表单</span>
    <span class="token function">onSubmit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 校验表单，用户名和密码都必须填入</span>
      <span class="token comment">// Element 表单校验规则配置，请查看https://element.eleme.cn/#/zh-CN/component/form</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>$refs<span class="token punctuation">[</span><span class="token string">&quot;form&quot;</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token parameter">valid</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>valid<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment">// 校验通过</span>
          <span class="token comment">// 设置用户名</span>
          <span class="token function">setGlobalData</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>form<span class="token punctuation">.</span>username<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token comment">// 跳转到里页</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>$router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">&quot;Home&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token comment">// 校验失败</span>
          <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_12-5-3-鉴权进入内页"><a href="#_12-5-3-鉴权进入内页" class="header-anchor">#</a> 12.5.3 鉴权进入内页</h3> <p>这里，我们需要使用 vue-router 的<code>router.beforeEach</code>导航守卫能力，当用户未登录时，则拒绝进入其他路由页面里：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// main.js</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> getGlobalData <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;utils/globalData&quot;</span><span class="token punctuation">;</span>

router<span class="token punctuation">.</span><span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">to<span class="token punctuation">,</span> <span class="token keyword">from</span><span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>to<span class="token punctuation">.</span>name <span class="token operator">!==</span> <span class="token string">&quot;Login&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 非 login 页面，检查是否登录</span>
    <span class="token comment">// 这里简单前端模拟是否填写了用户名，真实环境需要走后台登录，缓存到本地</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">getGlobalData</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">&quot;Login&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 其他情况正常执行</span>
  <span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><blockquote><p><a href="https://vue-eboook-1255459943.cos.ap-chengdu.myqcloud.com/12/1-element-manage-app/index.html" target="_blank" rel="noopener noreferrer">点击此处查看页面效果<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <a href="https://github.com/godbasin/vue-ebook/tree/vue-sourcecode/12/1-element-manage-app" target="_blank" rel="noopener noreferrer">点击此处查看源码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>这样，我们就可以在用户未登录时，拦截所有通往内页的操作，并重定向到登录页面。当然，这只是个静态页面，距离真正上线，我们还需要进行接口的联调、代码打包、发布上线等工作。但到这里，我们整个拥有登录、导航、数据增删改查的能力都开发完成了。</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/vue-ebook/edit/ebook-sourcecode/docs/vue-ebook/12.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本书采用“保持署名—非商用”<a href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">创意共享4.0许可证</a>。只要保持原作者署名和非商用，您可以自由地阅读、分享、修改本书。</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/vue-ebook/vue-ebook/11.html" class="prev">
          第11章 全局数据管理与 Vuex
        </a></span> <span class="next"><a href="/vue-ebook/vue-ebook/13.html">
          第13章 实战：表单配置化实现
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-7235" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty1.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/vue-ebook/assets/js/app.2f410bb9.js" defer></script><script src="/vue-ebook/assets/js/2.d60fd2a5.js" defer></script><script src="/vue-ebook/assets/js/3.c15c8d98.js" defer></script><script src="/vue-ebook/assets/js/11.6bf1fc64.js" defer></script>
  </body>
</html>
